#include <stdio.h>
#include <string.h>
#include "hashtable.h"
#include "hashtable_util.h"
int hash(char* buf, int hash_size){
    char* p = buf;
    long long acc = 0;
    while(*p!=0) {
	acc += *p;
	p++;
    }
    return (int)(acc % hash_size);
}

Hashtable* create_hashtable(int size){
    Hashtable* hashtable = new Hashtable;
    hashtable->bucket = new Node*[size];
    hashtable->size = size;
    hashtable->node_count = 0;
    hashtable->expand_thresold = default_expand_thresold;
    hashtable->shrink_thresold = default_shrink_thresold;
    for(int i=0; i<size; i++){
        hashtable->bucket[i] = create_node(NULL,NULL,NULL);
    }
    return hashtable;

}


Hashtable* create_hashtable(int size, float expand_thresold, float shrink_thresold){
    Hashtable* hashtable = create_hashtable(size);
    hashtable->expand_thresold = expand_thresold;
    hashtable->shrink_thresold = shrink_thresold;
    return hashtable;
}

Hashtable* hashtable_expand(Hashtable* hashtable){
    Hashtable* newHashtable = create_hashtable(hashtable->size*2, hashtable->expand_thresold, hashtable->shrink_thresold);
    Node* current = hashtable_getFirst(hashtable);
    while (hashtable_getNext(hashtable,current)!=NULL){
	hashtable_add(newHashtable,current->key, current->value);
	current = hashtable_getNext(hashtable,current);	
    }
    delete_hashtable(hashtable);
    return newHashtable;
}

Node* create_node(char* key, char* value, Node* pNext){
    Node* node = new Node;
    if (key!=NULL){
	node->key = new char[strlen(key)+1];
	strcpy(node->key,key);
    } else 
	node->key = NULL;
    if (value!=NULL){
	node->value = new char[strlen(value)+1];
	strcpy(node->value,value);
    } else
	node->value = NULL;
    node->pNext = pNext;
    return node;
}

void delete_node(Node* node){
    delete node->key;
    delete node->value;
    delete node;
}

void delete_hashtable(Hashtable* hashtable){
    Node* current = hashtable_getFirst(hashtable);
    while (current!=NULL){
	Node* next = hashtable_getNext(hashtable,current);
	delete_node(current);
	current = next;
    }
    delete hashtable->bucket;
    delete hashtable;
} 


void hashtable_add(Hashtable* hashtable, char* key, char* value){
    int pos = hash(key, hashtable->size);
    Node* currentNode = hashtable->bucket[pos];
    if (currentNode->key==NULL){
	delete_node(currentNode);
	currentNode=create_node(key,value,NULL);
    } else {
	while(currentNode->pNext!=NULL){
	    currentNode = currentNode->pNext;
	}
        currentNode->pNext = create_node(key,value,NULL);
    }
}


char* hashtable_find(Hashtable* hashtable, char* key){
    int pos = hash(key,hashtable->size);
    Node* currentNode = hashtable->bucket[pos];
    if (currentNode->key == NULL)
	return NULL;
    do {
	if (currentNode->key!=NULL && strcmp(currentNode->key,key)==0)
	    return currentNode->value;
	if (currentNode->pNext!=NULL){
	    currentNode = currentNode->pNext;
	} else return NULL;
    } while(true);
}
Node* hashtable_getFirst(Hashtable* hashtable){
    for (int i=0; i<hashtable->size; i++){
	if (hashtable->bucket[i]->key!=NULL){
	    return hashtable->bucket[i];
	}
    }
    return NULL;
}

Node* hashtable_getNext(Hashtable* hashtable, Node* node){
    if (node->pNext!=NULL)
	return node->pNext;
    int pos = hash(node->key,hashtable->size);
    for(int i=pos+1; i<hashtable->size; i++){
	if (hashtable->bucket[i]->key!=NULL)
	     return hashtable->bucket[i];
	}
    return NULL;
}

void hashtable_delete(Hashtable* hashtable, char* key){
    int pos = hash(key,hashtable->size);
    Node* currentNode = hashtable->bucket[pos];
    if (currentNode->key==NULL) return;
    if (strcmp(key, currentNode->key)==0){
	if (currentNode->pNext==NULL){
	    currentNode->key = NULL;
	    currentNode->value = NULL;
	} else {
	    Node* pNext = currentNode->pNext;
	    currentNode->key =pNext->key;
	    currentNode->value = pNext->value;
	    currentNode->pNext=pNext->pNext;
	    delete_node(pNext);
	}
    }
} 





